package com.plr.booker;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.NodeList;

public abstract class BookBase {

	static String POS;

	static {
		try {
			POS = readFile("POS/PROD.xml");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public abstract EndPoint getEndPoint();

	public void doit() {

		try {
			// Create SOAP Connection
			System.err.println(getEndPoint().getEndPoint());
			System.err.println(getEndPoint().getMethod());
			SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory
					.newInstance();
			doit(soapConnectionFactory);
		} catch (Exception e) {
			System.err
					.println("Error occurred while sending SOAP Request to Server");
			e.printStackTrace();
		}

		System.out.println("asdfasdfasdf");
	}

	private void doit(SOAPConnectionFactory soapConnectionFactory)
			throws SOAPException, Exception {

		SOAPConnection soapConnection = null;
		try {
			soapConnection = soapConnectionFactory.createConnection();
			// Send SOAP Message to SOAP Server
			// String url =
			// "http://ws.cdyne.com/emailverify/Emailvernotestemail.asmx";
			SOAPMessage soapResponse = soapConnection.call(
					createSOAPRequestAC2U(), getEndPoint().getEndPoint());

			// Process the SOAP Response
			printSOAPResponse(soapResponse);

		} finally {
			if (soapConnection != null) {
				soapConnection.close();
			}
		}
	}

	private SOAPMessage createSOAPRequestAC2U() throws Exception {
		MessageFactory messageFactory = MessageFactory
				.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
		SOAPMessage soapMessage = messageFactory.createMessage();

		SOAPPart soapPart = soapMessage.getSOAPPart();
		soapPart.getEnvelope().setPrefix("soap");

		// String serverURI = "http://ws.cdyne.com/";
		String serverURI = "http://schemas.xmlsoap.org/soap/envelope/";

		// SOAP Envelope
		SOAPEnvelope envelope = soapPart.getEnvelope();
		envelope.setPrefix("soap");

		envelope.addNamespaceDeclaration("xsi",
				"http://www.w3.org/2001/XMLSchema-instance");
		envelope.addNamespaceDeclaration("xsd",
				"http://www.w3.org/2001/XMLSchema");
		envelope.addNamespaceDeclaration("soap", serverURI);

		envelope.getHeader().setPrefix("soap");
		// SOAP Body
		SOAPBody soapBody = envelope.getBody();
		soapBody.setPrefix("soap");
		SOAPElement soapBodyElem = soapBody.addChildElement(getEndPoint()
				.getMethod(), "", "http://www.aircanada.com/ac2u/");

		SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("requestXML",
				"");

		String xml = readFile(getFile());

		xml = BookCommons.replace(xml, getFileParamMap());

		System.out.println(xml);

		writeToFileRQ(xml);

		soapBodyElem1.addTextNode(xml);

		MimeHeaders headers = soapMessage.getMimeHeaders();
		headers.addHeader("SOAPAction", "http://www.aircanada.com/ac2u/"
				+ getEndPoint().getMethod());

		soapMessage.saveChanges();

		Source sourceContent = soapMessage.getSOAPPart().getContent();

		/* Print the request message */
		System.out.print("Request SOAP Message = ");
		// StreamResult result = new StreamResult(System.out);
		// TransformerFactory transformerFactory = TransformerFactory
		// .newInstance();
		// Transformer transformer = transformerFactory.newTransformer();
		// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		// transformer.setOutputProperty(
		// "{http://xml.apache.org/xslt}indent-amount", "2");
		// transformer.transform(sourceContent, result);

		// soapMessage.writeTo(System.out);
		// System.out.println();

		return soapMessage;
	}

	private void writeToFileRQ(String xml) throws Exception {
		OutputStream output = BookCommons
				.createFile(getNewFileParamName(ComType.RQ));

		PrintWriter out = new PrintWriter(new OutputStreamWriter(output,
				"UTF-8"));
		out.write(xml);
		out.close();
	}

	static String readFile(String path) throws IOException {
		Charset encoding = Charset.forName("UTF-8");
		byte[] encoded = Files.readAllBytes(Paths.get(path));
		return encoding.decode(ByteBuffer.wrap(encoded)).toString();
	}

	/**
	 * Method used to print the SOAP Response
	 */
	void printSOAPResponse(SOAPMessage soapResponse) throws Exception {

		Source sourceContent = soapResponse.getSOAPPart().getContent();
		System.out.print("\nResponse SOAP Message = ");
		StreamResult result = new StreamResult(System.out);

		// StreamResult resultOut = new StreamResult(System.err);

		OutputStream newFile = BookCommons
				.createFile(getNewFileParamName(ComType.RS));
		StreamResult resultOut = new StreamResult(newFile);

		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		transformer.setOutputProperty(
				"{http://xml.apache.org/xslt}indent-amount", "2");
		transformer.transform(sourceContent, result);

		System.out.println();

		SOAPBody body = soapResponse.getSOAPBody();
		NodeList nl = body.getElementsByTagName(getEndPoint().getMethod()
				+ "Result");

		for (int i = 0; i < nl.getLength();) {
			org.w3c.dom.Node n = nl.item(i);

			Source test = new StreamSource(new StringReader(n.getTextContent()));

			transformer.transform(test, resultOut);
			break;
		}
	}

	public String getFile() {
		return null;
	}

	public Map<String, String> getFileParamMap() {
		return null;
	}

	String[] getNewFileParamName(ComType ct) {
		return null;
	}

}
